package erfgame.frontend.desktop.controller;

import java.awt.Component;
import java.awt.Container;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JComponent;
import javax.swing.SwingUtilities;

import erfgame.core.Dimensions3D;
import erfgame.core.Operation;
import erfgame.core.OperationResultListener;
import erfgame.core.memory.ByteArray3DMemoryPool;
import erfgame.core.memory.MemoryPool;
import erfgame.core.world.Frequency;
import erfgame.core.world.LongitudinalZone;
import erfgame.core.world.TerrainMaterialTypeWeight;
import erfgame.core.world.WorldDAOManager;
import erfgame.core.world.WorldGenerationParameters;
import erfgame.core.world.generator.WorldGeneratorUtils;
import erfgame.core.world.terrain.BlockSurfaceImageFactoryManager;
import erfgame.core.world.terrain.TerrainConstants;
import erfgame.core.world.terrain.TerrainMaterialType;

import erfgame.frontend.desktop.view.ViewActionListener;
import erfgame.frontend.desktop.view.operation.OperationViewController;
import erfgame.frontend.desktop.view.world.create.CreateWorldView;

public class CreateWorldController extends AbstractController {
	
	private static final Logger log = Logger.getLogger( CreateWorldController.class.getName() );
	
	private static final int DEFAULT_BLOCK_WIDTH = 128;
	private static final int DEFAULT_BLOCK_HEIGHT = 128;
	private static final int DEFAULT_BLOCK_DEPTH = 9;
	
	private static final int DEFAULT_GRID_DIAGONAL = 32;
	
	private static final int DEFAULT_WORLD_WIDTH = 4;
	private static final int DEFAULT_WORLD_HEIGHT = 3;
	private static final int DEFAULT_WORLD_DEPTH = 8;
	
	private static final int DEFAULT_SEA_LEVEL = DEFAULT_BLOCK_DEPTH * 2;
	
	private static final long DEFAULT_WORLD_AGE = 400;
	
	private static final LongitudinalZone DEFAULT_NORTHERN_ZONE = LongitudinalZone.polar;
	private static final LongitudinalZone DEFAULT_SOUTHERN_ZONE = LongitudinalZone.tropical;
	
	private Container container;
	private Object constraints;
	private CreateWorldView view;
	private WorldDAOManager worldDAOManager;
	private WorldGenerationParameters parameters;
	private BlockSurfaceImageFactoryManager imageFactoryManager;
	
	public CreateWorldController( WorldDAOManager worldDAOManager, BlockSurfaceImageFactoryManager imageFactoryManager ) {
		this.worldDAOManager = worldDAOManager;
		this.imageFactoryManager = imageFactoryManager;
		this.view = new CreateWorldView();		
		this.view.addViewActionListener( new ViewActionListener() {

			public void actionPerformed(Object source, int actionType, Object operation) {
				switch( actionType ) {
				case CreateWorldView.ACTION_TYPE_CANCEL: 
					fireControllerCompleted();
					break;
				case CreateWorldView.ACTION_TYPE_CREATE:
					createWorld( parameters );
					break;
				}
			}
		});
	}
	
	@SuppressWarnings(value="unchecked")
	private void createWorld( WorldGenerationParameters parameters ) {
//		Container container = ((JComponent)this.container).getTopLevelAncestor();
//		Frame frame;
//		if( container instanceof Frame ) {
//			frame = (Frame)container;
//		} else {
//			frame = null;
//		}
//		final JDialog dialog = new JDialog(frame, "Progress", true);
//		
//		OperationViewController operationController;
//		operationController = new OperationViewController();
//		
//		final Operation<Void, RuntimeException> operation;
//		operation = WorldGeneratorUtils.generate(worldDAOManager, imageFactoryManager, parameters);
//		operationController.setOperation(operation);
//		
//		OperationView operationView = operationController.getView();
//		
//		dialog.add( operationView.getComponent() );
//		dialog.setDefaultCloseOperation( JDialog.DO_NOTHING_ON_CLOSE );
//		dialog.pack();
//		dialog.setResizable(false);
//		dialog.setLocation(
//				frame.getX() + (frame.getWidth() - dialog.getWidth())/2, 
//				frame.getY() + (frame.getHeight() - dialog.getHeight())/2
//		);
//		
//		Thread thread = new Thread() {
//			@Override
//			public void run() {
//				try {
//					operation.perform();
//					fireControllerCompleted();
//				} catch( Exception ex ) {
//					// TODO error dialog
//					ex.printStackTrace();
//				} finally {
//					dialog.setVisible(false);
//				}
//			}
//		};
//		thread.start();
//		
//		dialog.setVisible(true);
		Dimensions3D blockDimensions = parameters.getBlockDimensions();
		// TODO : this should probably come from config		
		MemoryPool<byte[][][]> terrainMemoryPool = new ByteArray3DMemoryPool(
				blockDimensions.width, 
				blockDimensions.height, 
				blockDimensions.depth
		);
		
		final Operation<Void, RuntimeException> operation;
		operation = WorldGeneratorUtils.generate(worldDAOManager, imageFactoryManager, parameters, terrainMemoryPool);
		OperationViewController.showOperationDialog(
				operation, 
				(JComponent)this.container,
				new OperationResultListener() {

					public void failure(Throwable error) {
						// TODO error dialog'
						log.log( Level.SEVERE, "unable to create world", error );
						
					}

					public void success(Object result) {
						fireControllerCompleted();
					}
				}
				
		);
		
	}
	
	public void start( Container container, Object constraints ) {
		this.container = container;
		this.constraints = constraints;
		
		int nextWorldId = WorldGeneratorUtils.getNextWorldId(worldDAOManager);
		
		WorldGenerationParameters parameters;
		// TODO this should be retrieved from config
		parameters = new WorldGenerationParameters();
		
		parameters.setWorldName( "World "+nextWorldId );
		
		parameters.setBlockDimensions(new Dimensions3D(DEFAULT_BLOCK_WIDTH,DEFAULT_BLOCK_HEIGHT,DEFAULT_BLOCK_DEPTH));
		parameters.setGridDiagonal(DEFAULT_GRID_DIAGONAL);
		parameters.setWorldBlocks(new Dimensions3D(DEFAULT_WORLD_WIDTH,DEFAULT_WORLD_HEIGHT,DEFAULT_WORLD_DEPTH));
		
		parameters.setAgeOfEarthDuration( (int)DEFAULT_WORLD_AGE );
		parameters.setAgeOfPlantsDuration( (int)DEFAULT_WORLD_AGE );
		parameters.setAgeOfAnimalsDuration( (int)DEFAULT_WORLD_AGE );
		parameters.setAgeOfManDuration( (int)DEFAULT_WORLD_AGE );
		
		parameters.setStartingLandLevel( DEFAULT_SEA_LEVEL/2 );
		parameters.setSeaLevel( DEFAULT_SEA_LEVEL );
		parameters.setNumberOfTectonicPlates(4);
		parameters.setVolcanicActivity( Frequency.uncommon );
		
		parameters.setNorthernmostZone( DEFAULT_NORTHERN_ZONE );
		parameters.setSouthernmostZone( DEFAULT_SOUTHERN_ZONE );
		
		this.parameters = parameters;
		
		this.view.init( parameters );
		showCreateWorldView();
	}
	
	public void showCreateWorldView() {
		// TODO : ensure is done in event thread
		SwingUtilities.invokeLater( new Runnable() {
			public void run() {
				CreateWorldController.this.container.removeAll();
				Component component = CreateWorldController.this.view.getComponent(); 
				CreateWorldController.this.container.add( 
						component, 
						CreateWorldController.this.constraints 
				);
				CreateWorldController.this.container.validate();				
				CreateWorldController.this.container.repaint();				
			}
		});
	}
	
}
